#!/usr/bin/python
# -*- coding: utf-8 -*-

import Ice, IceStorm
import sys, os, thread

try:
    HOME = os.environ['FIPA']
except KeyError:
    print 'FIPA environment variable is not currently defined.'
    sys.exit(0)

SLICE = os.path.join(HOME, 'slice')
FILE1 = os.path.join(SLICE, 'FIPA.ice')
Ice.loadSlice('--all -I/usr/share/slice', ['-I' + SLICE, FILE1])

import FIPA, ASD

class DFI (FIPA.DF, ASD.Listener, ASD.Search):

    def __init__ (self, adapter):
        self.__mutex = thread.allocate_lock()
        # Key   ==> Object identity.
        # Value ==> DF's agent description.
        self.__agents = {}
        #self.__dfAgentDescriptions = {}
        
        # Relevant proxies.
        self.__proxies = {}
        
        # Reference to the topic manager.
        try:
            base = adapter.getCommunicator().stringToProxy('FIPA.IceStorm/TopicManager')
            self.__proxies['topicManager'] = IceStorm.TopicManagerPrx.checkedCast(base)
        except Ice.Exception, ex:
            sys.stdout.write('Invalid TopicManager: ' + str(ex))
            raise Ice.Exception

        # DF channel.
        try:
            self.__proxies['DF'] = self.__proxies['topicManager'].retrieve("DF");
            sys.stdout.write('Topic DF retrieved!' + '\n')
        except IceStorm.NoSuchTopic:
            self.__proxies['DF'] = self.__proxies['topicManager'].create("DF")
            sys.stdout.write('Topic DF created!' + '\n')

        # TODO: think about the link with the ASDF.
        # ASDA channel.
        try:
            self.__proxies['ASDA'] = self.__proxies['topicManager'].retrieve("ASDA");
            sys.stdout.write('Topic ASDA retrieved!' + '\n')
        except IceStorm.NoSuchTopic:
            self.__proxies['ASDA'] = self.__proxies['topicManager'].create("ASDA")
            sys.stdout.write('Topic ASDA created!' + '\n')

        pub = self.__proxies['ASDA'].getPublisher()
        self.__proxies['listener'] = FIPA.AgentPrx.uncheckedCast(pub)

        # ASDL channel.
        try:
            self.__proxies['ASDL'] = self.__proxies['topicManager'].retrieve("ASDL");
            sys.stdout.write('Topic ASDL retrieved!' + '\n')
        except IceStorm.NoSuchTopic:
            self.__proxies['ASDL'] = self.__proxies['topicManager'].create("ASDL")
            sys.stdout.write('Topic ASDL created!' + '\n')

        pub = self.__proxies['ASDL'].getPublisher()
        self.__proxies['search'] = FIPA.AgentPrx.uncheckedCast(pub)

    # Register a new agent description with the DF.
    def register (self, dfAgentDescription, curr):
        self.__mutex.acquire()
        if self.__agents.has_key(dfAgentDescription.name.ice_getIdentity()):
            self.__mutex.release()
            raise FIPA.AgentExists
        else:            
            self.__agents[dfAgentDescription.name.ice_getIdentity()] = dfAgentDescription
            #print str(dfAgentDescription.name.ice_getIdentity().name) + ' registered with the DF.'
            self.__mutex.release()

        # Advise the other subscribers.
        self.notify(FIPA.DFAction.Registration, dfAgentDescription)

    # Deregister an agent description with the DF.
    def deregister (self, id, curr = None):
        self.__mutex.acquire()
        try:
            # Advise the other subscribers.
            self.notify(FIPA.DFAction.Deregistration, self.__agents.pop(id))
        except KeyError:
            pass
        self.__mutex.release()

    # Mofity an agent description with the DF.
    def modify (self, dfAgentDescription, curr = None):
        self.__mutex.acquire()
        if self.__agents.has_key(dfAgentDescription.name.ice_getIdentity()):
            self.__agents[dfAgentDescription.name.ice_getIdentity()] = dfAgentDescription
            # Advise the other subscribers.
            self.notify(FIPA.DFAction.Modification, dfAgentDescription)
        self.__mutex.release()

    def search (self, dfAgentDescription, curr = None):
        # TODO: search mechanism.
        agents = []
        for desc in self.__agents.values():
            # Math the name of the service.
            for serv in desc.services:
                if dfAgentDescription.services[0].name == serv.name:
                    agents.append(desc.name)

        return agents

    def subscribe (self, aid, curr):
        # Subscription to the DF event channel.
        try:
            self.__proxies['DF'].subscribeAndGetPublisher(None, aid)
            #print str(aid.ice_getIdentity().name) + ' subscribed with the DF.'
        except IceStorm.AlreadySubscribed:
            raise FIPA.AlreadySubscribed
           
    def unsubscribe (self, prx, curr):
        # Unsubscribe the agent to the DF channels.
        self.__proxies['DF'].unsubscribe(prx)
        #print str(prx.ice_getIdentity().name) + ' unsubscribed with the DF.'

    def notify (self, act, desc):
        pub = self.__proxies['DF'].getPublisher()
        agent = FIPA.AgentPrx.uncheckedCast(pub)
        agent.dfAdv(act, desc)

    ##### From ASD.Listener.

    # ASD.Listener adv()
    def adv (self, prx, curr):
        # TODO
        pass

    # ASD.Listener bye()
    def bye (self, oid, curr):
        # TODO
        pass

    ##### From ASD.Search.

    # ASD.Search lookup()
    def lookup (self, cb, tid, query, curr = None):
        # TODO
        pass

    # ASD.Search discover()
    def discover (self, curr):
        # TODO
        pass
